package com.newasia.server.common.interceptor;

import com.newasia.server.common.tool.CheckObjectIsNullUtils;
import com.newasia.server.dal.entitys.paramValue.HistoryParam;
import com.newasia.server.dal.persistence.MonitorDetailMapper;
import com.newasia.server.serviceImpl.UserServiceImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.Executor;
import org.apache.ibatis.executor.parameter.ParameterHandler;
import org.apache.ibatis.executor.statement.StatementHandler;
import org.apache.ibatis.mapping.BoundSql;
import org.apache.ibatis.mapping.MappedStatement;
import org.apache.ibatis.plugin.*;
import org.apache.ibatis.reflection.DefaultReflectorFactory;
import org.apache.ibatis.reflection.MetaObject;
import org.apache.ibatis.reflection.SystemMetaObject;
import org.apache.ibatis.scripting.defaults.DefaultParameterHandler;
import org.apache.ibatis.session.ResultHandler;
import org.apache.ibatis.session.RowBounds;

import java.lang.reflect.Method;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.Properties;

import static com.newasia.server.common.tool.CheckObjectIsNullUtils.checkObjIsNull;

/**
 * @author LiChong
 * @description mybaits插件生成平行表
 * @date 2020/5/13
 */
@Intercepts(value = {@Signature(
        type = StatementHandler.class,
        method = "prepare",
        args = {
                Connection.class,
                Integer.class
        }
)})
@Slf4j
public class SplicingTableInterceptor implements Interceptor {

    @Override
    public Object intercept(Invocation invocation) throws Throwable {
        StatementHandler handler = (StatementHandler) invocation.getTarget();
        handler.getBoundSql();
        // 获取指定对象的元信息
        MetaObject metaObject = SystemMetaObject.forObject(handler);
        // mappedStatement 包含了Sql的信息
        // 分离代理对象链(由于目标类可能被多个插件拦截，从而形成多次代理，通过下面的两次循环
        // 可以分离出最原始的的目标类)
        while (metaObject.hasGetter("h")) {
            Object object = metaObject.getValue("h");
            metaObject = SystemMetaObject.forObject(object);
        }
        // 分离最后一个代理对象的目标类
        while (metaObject.hasGetter("target")) {
            Object object = metaObject.getValue("target");
            metaObject = SystemMetaObject.forObject(object);
        }
        MappedStatement mappedStatement = (MappedStatement)metaObject.getValue("delegate.mappedStatement");

        // 获取statement id
        String statementId = mappedStatement.getId();
        if (statementId.contains("HistoryMapper")){
            BoundSql boundSql = handler.getBoundSql();
            String sql = boundSql.getSql();
            boundSql.getParameterObject();

            Connection conn = (Connection) invocation.getArgs()[0];
            PreparedStatement ps = conn.prepareStatement(sql);
            // 获取参数处理器来处理参数
            //ParameterHandler ph = (ParameterHandler) metaObject.getValue("delegate.parameterHandler");
            //ph.setParameters(ps);

            Object parameterObject = boundSql.getParameterObject();
            setParameters(ps,mappedStatement,boundSql,parameterObject);
            if(parameterObject instanceof HistoryParam){
                HistoryParam param = (HistoryParam)parameterObject;
                //定位sid所在的历史数据表
                String locationSql = "SELECT data FROM siddata where SID = '"+param.getSid()+"'";
                PreparedStatement locationPs = conn.prepareStatement(locationSql);
                // 执行查询
                ResultSet rs = locationPs.executeQuery();
                if(rs.next()){
                    String location = rs.getString(1);
                    sql = sql.replaceAll("mindata","xgrpc202005.dbo.mindata"+location);
                }
            }
            //metaObject.setValue("delegate.boundSql.sql", sql);
            metaObject.setValue("delegate.boundSql.sql", sql);
        }
        return invocation.proceed();
    }

    /*private void setPageParameter(HistoryParam param, Connection connection, MappedStatement mappedStatement,
                                  BoundSql boundSql) {
        // 记录总记录数
        String locationSql = "SELECT data FROM siddata where SID = '"+param.getSid()+"'";

        PreparedStatement countStmt = null;
        ResultSet rs = null;
        try {
            countStmt = connection.prepareStatement(countSql);
            BoundSql countBS = new BoundSql(mappedStatement.getConfiguration(), countSql,
                    boundSql.getParameterMappings(), boundSql.getParameterObject());
            setParameters(countStmt, mappedStatement, countBS, boundSql.getParameterObject());
            rs = countStmt.executeQuery();
            int totalCount = 0;
            if (rs.next()) {
                totalCount = rs.getInt(1);
            }
            page.setTotal(totalCount);
            int totalPage = totalCount / page.getPageSize() + ((totalCount % page.getPageSize() == 0) ? 0 : 1);
            page.setPages(totalPage);
        } catch (SQLException e) {
            log.error("Ignore this exception", e);
        } finally {
            try {
                rs.close();
            } catch (SQLException e) {
                log.error("Ignore this exception", e);
            }
            try {
                countStmt.close();
            } catch (SQLException e) {
                log.error("Ignore this exception", e);
            }
        }
    }*/

    /**
     *代入参数值
     * @author LiChong
     * @date 2020/5/27
     * @param  * @param ps
     * @param mappedStatement
     * @param boundSql
     * @param parameterObject
     * @return void
     */
    private void setParameters(PreparedStatement ps, MappedStatement mappedStatement, BoundSql boundSql,
                               Object parameterObject) throws SQLException {
        ParameterHandler parameterHandler = new DefaultParameterHandler(mappedStatement, parameterObject, boundSql);
        parameterHandler.setParameters(ps);
    }

    @Override
    public Object plugin(Object target) {
        if (target instanceof StatementHandler){
            return Plugin.wrap(target, this);
        }
        return target;
    }

    @Override
    public void setProperties(Properties properties) {

    }
}
